/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.web.controller;

import net.sf.cglib.beans.BeanMap;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.propertyeditors.CustomCollectionEditor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.vacoor.nothing.common.util.StringUtils;

import java.beans.PropertyEditorSupport;
import java.util.Arrays;
import java.util.List;

/**
 * @author vacoor
 */
public abstract class ControllerSupport {
    private String viewPrefix;

    protected ControllerSupport() {
        setViewPrefix(defaultViewPrefix());
    }

    public String getViewPrefix() {
        return viewPrefix;
    }

    public void setViewPrefix(String viewPrefix) {
        viewPrefix = viewPrefix.startsWith("/") ? viewPrefix : "/" + viewPrefix;
        this.viewPrefix = !viewPrefix.endsWith("/") ? viewPrefix : viewPrefix.substring(0, viewPrefix.length() - 1);
    }

    /**
     * 获取当前命名空间下的 view 的路径
     */
    protected String getViewPath(String path) {
        String prefix = getViewPrefix();

        if (null == path) {
            return prefix;
        }

        return prefix + (path.startsWith("/") ? path : "/" + path);
    }

    /**
     * 获取当前命名空间下的 view 重定向字符串路径
     * eg: / -> redirect: /namespace/
     *
     * @param path
     * @return
     */
    protected String redirectViewPath(String path) {
        return "redirect:" + getViewPath(path);
    }

    /**
     * 获取默认的命名空间 (class 上 RequestMapping#value 第一个值)
     */
    protected String defaultViewPrefix() {
        String currentViewPrefix = "";
        RequestMapping requestMapping = AnnotationUtils.findAnnotation(getClass(), RequestMapping.class);
        if (requestMapping != null && requestMapping.value().length > 0) {
            currentViewPrefix = requestMapping.value()[0];
        }
        return currentViewPrefix;
    }


    /* *****************************************************
     *
     * *****************************************************/

    /**
     * Collection&lt;String&gt; --> Collection&lt;Element&gt;
     */
    protected static class CustomStringCollectionToBeanCollectionPropertyEditor extends CustomCollectionEditor {
        private final CustomStringToBeanPropertyEditor propertyEditor;


        public CustomStringCollectionToBeanCollectionPropertyEditor(Class<?> collectionType, Class<?> beanType) {
            this(collectionType, beanType, "id", new String[0]);
        }

        public CustomStringCollectionToBeanCollectionPropertyEditor(Class<?> collectionType, Class<?> beanType, String property, String[] skipValues) {
            super(collectionType);
            Assert.notNull(beanType);
            Assert.notNull(property);
            propertyEditor = new CustomStringToBeanPropertyEditor(beanType, property, skipValues);
        }

        public CustomStringCollectionToBeanCollectionPropertyEditor(Class<?> collectionType, boolean nullAsEmptyCollection, Class<?> beanType, String property, String[] skipValues) {
            super(collectionType, nullAsEmptyCollection);
            Assert.notNull(beanType);
            Assert.notNull(property);
            propertyEditor = new CustomStringToBeanPropertyEditor(beanType, property, skipValues);
        }

        @Override
        public void setValue(Object value) {
            if (null != value && value instanceof String) {
                value = ((String) value).split(",\\s*");
            }
            super.setValue(value);
        }

        @Override
        protected Object convertElement(Object element) {
            propertyEditor.setValue(element);
            return propertyEditor.getValue();
        }
    }

    /**
     * String --> Bean
     */
    protected static class CustomStringToBeanPropertyEditor extends PropertyEditorSupport {
        private final Class<?> clazz;
        private final String property;
        private final List<String> skipValues;

        public CustomStringToBeanPropertyEditor(Class<?> clazz) {
            this(clazz, new String[0]);
        }

        public CustomStringToBeanPropertyEditor(Class<?> clazz, String[] skipValues) {
            this(clazz, "id", skipValues);
        }

        public CustomStringToBeanPropertyEditor(Class<?> clazz, String property, String[] skipValues) {
            Assert.notNull(clazz);
            Assert.notNull(property);
            this.clazz = clazz;
            this.property = property;
            this.skipValues = Arrays.asList(null != skipValues ? skipValues : new String[0]);
        }

        @Override
        public void setValue(Object value) throws IllegalArgumentException {
            String text;
            if ((value instanceof String) && StringUtils.hasText(text = (String) value) && !skipValues.contains(text)) {
                Object bean = BeanUtils.instantiate(clazz);
                BeanMap beanMap = BeanMap.create(bean);
                beanMap.put(property, text);
                value = beanMap.getBean();
            }
            super.setValue(value);
        }
    }
}
